package com.cloudwise.service.impl;

import cn.hutool.core.date.DateTime;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.cloudwise.config.AliyunOssConfig;
import com.cloudwise.entity.UploadResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author Enzo
 * @version 1.0
 * @date Created at 2020/12/23 16:10
 * @description upload service
 * @modifiedBy
 */
@Service
public class UploadFileService {
    @Autowired
    private OSS ossClient;
    @Autowired
    private AliyunOssConfig aliyunOssConfig;


    /**
     * 上传文件并返回文件地址
     *
     * @param uploadFile 传入的文件
     * @return UploadResult 实体类
     * @createBy Enzo
     * @createTime 2020/12/25 11:02
     */
    public UploadResult upload(MultipartFile uploadFile, String idName) {

        //封装Result对象，并且将文件的byte数组放置到result对象中
        UploadResult fileUploadResult = new UploadResult();
        //获取原始文件名
        String fileName = uploadFile.getOriginalFilename();
        //将原始文件名修改成新文件名，防止重名覆盖
        String filePath = getFilePath(fileName, idName);
        // 上传到阿里云
        try {
            ossClient.putObject(aliyunOssConfig.getBucketName(), filePath, new
                    ByteArrayInputStream(uploadFile.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
            //上传失败
            fileUploadResult.setStatus("error");
            return fileUploadResult;
        }
        fileUploadResult.setFileName(fileName);
        fileUploadResult.setStatus("done");
        fileUploadResult.setResponse("success");
        fileUploadResult.setName(this.aliyunOssConfig.getUrlPrefix() + filePath);
        fileUploadResult.setUid(String.valueOf(System.currentTimeMillis()));
        return fileUploadResult;
    }

    /**
     * 上传文件并返回文件地址
     *
     * @param uploadFile 传入的文件
     * @return UploadResult 实体类
     * @createBy Enzo
     * @createTime 2020/12/25 11:02
     */
    public UploadResult upload(MultipartFile uploadFile) {

        //封装Result对象，并且将文件的byte数组放置到result对象中
        UploadResult fileUploadResult = new UploadResult();
        //获取原始文件名
        String fileName = uploadFile.getOriginalFilename();
        //将原始文件名修改成新文件名，防止重名覆盖
        String filePath = getFilePath(fileName);
        // 上传到阿里云
        try {
            ossClient.putObject(aliyunOssConfig.getBucketName(), filePath, new
                    ByteArrayInputStream(uploadFile.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
            //上传失败
            fileUploadResult.setStatus("error");
            return fileUploadResult;
        }
        fileUploadResult.setFileName(fileName);
        fileUploadResult.setStatus("done");
        fileUploadResult.setResponse("success");
        fileUploadResult.setName(this.aliyunOssConfig.getUrlPrefix() + filePath);
        fileUploadResult.setUid(String.valueOf(System.currentTimeMillis()));
        return fileUploadResult;
    }

    /**
     * 生成路径以及文件名 例如：//myFile/99Enzo/2020/07/22/75564277467979898.jpg
     *
     * @param sourceFileName 原文件名
     * @param idName         客户编号和姓名
     * @return String getFilePath
     * @createBy Enzo
     * @createTime 2020/12/23 17:13
     */
    private String getFilePath(String sourceFileName, String idName) {
        DateTime dateTime = new DateTime();
        return "myFile/" + idName + "/" + dateTime.toString("yyyy")
                + "/" + dateTime.toString("MM") + "/"
                + dateTime.toString("dd") + "/" + System.currentTimeMillis() + "/" + sourceFileName;
    }

    /**
     * 生成路径以及文件名 例如：//images/2020/07/22/75564277467979898.jpg
     *
     * @param sourceFileName 原文件名
     * @return String getFilePath
     * @createBy Enzo
     * @createTime 2020/12/23 17:13
     */
    private String getFilePath(String sourceFileName) {
        DateTime dateTime = new DateTime();
        return "myFile/" + dateTime.toString("yyyy")
                + "/" + dateTime.toString("MM") + "/"
                + dateTime.toString("dd") + "/" + System.currentTimeMillis() + "/" + sourceFileName;
    }

    /**
     * 查看文件列表
     *
     * @return List<OSSObjectSummary>
     * @createBy Enzo
     * @createTime 2020/12/23 17:18
     */
    public List<OSSObjectSummary> list() {
        // 设置最大个数。
        final int maxKeys = 200;
        // 列举文件。
        ObjectListing objectListing = ossClient.listObjects(new ListObjectsRequest(aliyunOssConfig.getBucketName()).withMaxKeys(maxKeys));
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
        return sums;
    }

    /**
     * 文件删除
     *
     * @param objectName 文件名
     * @return UploadResult
     * @createBy Enzo
     * @createTime 2020/12/23 17:20
     */
    public UploadResult delete(String objectName) {
        // 根据BucketName,objectName删除文件
        ossClient.deleteObject(aliyunOssConfig.getBucketName(), objectName);
        UploadResult fileUploadResult = new UploadResult();
        fileUploadResult.setName(objectName);
        fileUploadResult.setStatus("removed");
        fileUploadResult.setResponse("success");
        return fileUploadResult;
    }

    /**
     * 文件下载
     *
     * @param os
     * @param objectName
     * @createBy Enzo
     * @createTime 2020/12/23 17:21
     */
    public void exportOssFile(OutputStream os, String objectName) throws IOException {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(aliyunOssConfig.getBucketName(), objectName);
        // 读取文件内容。
        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
        BufferedOutputStream out = new BufferedOutputStream(os);
        byte[] buffer = new byte[1024];
        int lenght = 0;
        while ((lenght = in.read(buffer)) != -1) {
            out.write(buffer, 0, lenght);
        }
        if (out != null) {
            out.flush();
            out.close();
        }
        if (in != null) {
            in.close();
        }
    }


    /**
     * 批量下载oss文件并打成zip返回到response中
     *
     * @param fileNames   oss上的文件名集合
     * @param zipFileName 压缩包文件名
     * @param response    HttpServletResponse
     * @createBy Enzo
     * @createTime 2021/1/29 21:34
     */
    public void batchDownLoadOssFile(List<String> fileNames, String zipFileName, HttpServletResponse response) {
        /**
         * 阿里云API的内或外网域名  //替换成自己的
         */
        String ENDPOINT = aliyunOssConfig.getEndpoint();
        /**
         * 阿里云API的密钥Access Key ID   //替换成自己的
         */
        String ACCESS_KEY_ID = aliyunOssConfig.getAccessKeyId();
        /**
         * 阿里云API的密钥Access Key Secret   //替换成自己的
         */
        String ACCESS_KEY_SECRET = aliyunOssConfig.getAccessKeySecret();
        /**
         * 阿里云API的bucket名称    //替换成自己的
         */
        String BACKET_NAME = aliyunOssConfig.getBucketName();
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName=" + zipFileName + ".zip");
        BufferedInputStream bis = null;
        try {
            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
            OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            int sortNum = 0;
            for (String fileName : fileNames) {
                Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BACKET_NAME, fileName, HttpMethod.GET);
                // 设置过期时间。
                request.setExpiration(expiration);
                // 生成签名URL（HTTP GET请求）。
                URL signedUrl = ossClient.generatePresignedUrl(request);
                // 使用签名URL发送请求。
                OSSObject ossObject = ossClient.getObject(signedUrl, new HashMap<>());

                if (ossObject != null) {
                    InputStream inputStream = ossObject.getObjectContent();
                    byte[] buffs = new byte[1024 * 10];

                    String zipFile = sortNum + "_" + fileName.substring(fileName.lastIndexOf("/") + 1);
                    ZipEntry zipEntry = new ZipEntry(zipFile);
                    zos.putNextEntry(zipEntry);
                    bis = new BufferedInputStream(inputStream, 1024 * 10);

                    int read;
                    while ((read = bis.read(buffs, 0, 1024 * 10)) != -1) {
                        zos.write(buffs, 0, read);
                    }
                    ossObject.close();
                }
                sortNum++;
            }
            zos.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if (null != bis) {
                    bis.close();
                }
                response.getOutputStream().flush();
                response.getOutputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
